﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.ComponentModel;

//基于UDP 方式通信的【加减乘除】运算  所有的类都写到一块了 
namespace Proxy
{
    //定义接口
    public interface IArithmetic
    {
        float Add(float f1, float f2);
        float Sub(float f1, float f2);
        float Multiply(float f1, float f2);
        float Divide(float f1, float f2);
    }

    //实现接口的具体类
    public class Arithmetic : IArithmetic
    {
        private UdpClient ServerListen;
        private IPEndPoint RemotePoint;
        private IPEndPoint LocakPoint;
        private Thread ReciveThread = null;
        private byte[] RecDataBuf = new byte[1024 * 2];
        private string EncryptChar = "***";
        private char[] SpliceArr = new char[] { ',' };

        public static Arithmetic GetArithmetic(string localIp, int port)
        {
            try
            {
                IPEndPoint ip = new IPEndPoint(IPAddress.Parse(localIp), port);
                Arithmetic ari = new Arithmetic();
                ari.ServerListen = new UdpClient(ip);
                ari.LocakPoint = ip;
                return ari;
            }

            catch (Exception ex)
            {
                Console.WriteLine("记录异常日志：{0}", ex.StackTrace);
                return null;
            }
        }

        private Arithmetic()
        {
        }

        public void Start()
        {
            ReciveThread = new Thread(ReciveData);
            ReciveThread.IsBackground = true;
            ReciveThread.Start();
        }

        public void Close()
        {
            if (ReciveThread != null && ReciveThread.IsAlive)
            {
                ReciveThread.Abort();
            }
            ReciveThread = null;
            if (ServerListen != null)
            {
                ServerListen.Close();
            }
        }
        /// <summary>
        /// udp 不停接收数据
        /// </summary>
        private void ReciveData()
        {
            byte[] replyBuff;
            int sendInt;
            while (true)
            {
                RecDataBuf = ServerListen.Receive(ref RemotePoint);
                string operVal = GetOPeration(RecDataBuf);
                if (string.IsNullOrEmpty(operVal))
                {
                    //没有得到正确结果
                    replyBuff = Encoding.UTF8.GetBytes(this.EncryptChar + this.EncryptChar);
                }
                else
                {
                    //有结果值
                    replyBuff = Encoding.UTF8.GetBytes(this.EncryptChar + operVal + this.EncryptChar);
                }
                try
                {
                    //回复结果
                    sendInt = ServerListen.Send(replyBuff, replyBuff.Length, RemotePoint);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("错误信息：{0}", ex.Message);
                }
            }
        }

        private string GetOPeration(byte[] bts)
        {
            string operStr = string.Empty;
            //1. 获取得到的字符串信息
            string recStr = Encoding.UTF8.GetString(bts);
            if (!recStr.StartsWith(EncryptChar) || !recStr.EndsWith(EncryptChar))
            {
                return operStr;
            }
            string[] strArr = recStr.Replace(EncryptChar, "").Split(SpliceArr, StringSplitOptions.RemoveEmptyEntries);
            if (strArr.Length != 3)
            {
                return operStr;
            }
            //1.1 获取操作数
            float fOne, fTwo;
            if (!float.TryParse(strArr[0], out fOne) || !float.TryParse(strArr[2], out fTwo))
            {
                return operStr;
            }
            //2. 获取运算符的枚举值
            OperatorEnum oper = Util.ConverToEnum<OperatorEnum>(strArr[1]);
            switch (oper)
            {
                case OperatorEnum.Null:
                    break;
                case OperatorEnum.Add:
                    operStr = Add(fOne, fTwo).ToString();
                    break;
                case OperatorEnum.Sub:
                    operStr = Sub(fOne, fTwo).ToString();
                    break;
                case OperatorEnum.Multiply:
                    operStr = Multiply(fOne, fTwo).ToString();
                    break;
                case OperatorEnum.Divide:
                    float divVal = Divide(fOne, fTwo);
                    if (divVal == float.MinValue)
                    {
                        return operStr;
                    }
                    operStr = divVal.ToString();
                    break;
                default:
                    break;
            }
            return operStr;
        }


        public float Add(float f1, float f2)
        {
            return f1 + f2;
        }

        public float Divide(float f1, float f2)
        {
            if (f2 == 0)
            {
                return float.MinValue;
            }
            return f1 / f2;
        }

        public float Multiply(float f1, float f2)
        {
            return f1 * f2;
        }

        public float Sub(float f1, float f2)
        {
            return f1 - f2;
        }
    }

    //运算符枚举值
    public enum OperatorEnum
    {
        [Description("Null")]
        Null = 0,
        [Description("Add")]
        Add = 1,
        [Description("Sub")]
        Sub = 2,
        [Description("Mul")]
        Multiply = 3,
        [Description("Div")]
        Divide = 4,
    }

    //常规方法
    public class Util
    {
        public static T ConverToEnum<T>(string enumStr)
        {
            T result = default(T);
            Type type = typeof(T);
            Type descType = typeof(DescriptionAttribute);
            var fileInfos = type.GetFields();
            for (int i = 0; i < fileInfos.Length; i++)
            {
                var objs = fileInfos[i].GetCustomAttributes(descType, false);
                if (objs == null || objs.Length == 0)
                {
                    continue;
                }
                string descStr = ((DescriptionAttribute)objs[0]).Description;
                if (descStr == enumStr)
                {
                    result = (T)Enum.Parse(type, fileInfos[i].Name);
                    break;
                }
            }
            return result;
        }

        public static string GetEnumDescription<T>(T enumVal)
        {
            string enumStr = enumVal.ToString();
            var field = enumVal.GetType().GetField(enumStr);
            var objs = field.GetCustomAttributes(typeof(DescriptionAttribute), false);
            if (objs == null || objs.Length == 0)
            {
                return string.Empty;
            }
            return ((DescriptionAttribute)objs[0]).Description;
        }
    }



    //代理类  可以放到任何终端进行调用，只要网络能畅通
    public class ArithmeticProxy : IArithmetic
    {
        private UdpClient SendClient;

        private StringBuilder SendSb = new StringBuilder();

        private string EncryptionChar = "***";

        private IPEndPoint ServerIpPoint;

        private string RecOperResultStr = string.Empty;

        private IPEndPoint RemontIP = new IPEndPoint(IPAddress.Any, 0);

        public ArithmeticProxy(string serverIP, int port)
        {
            SendClient = new UdpClient(new IPEndPoint(IPAddress.Any, 0));
            ServerIpPoint = new IPEndPoint(IPAddress.Parse(serverIP), port);
        }
        public float Add(float f1, float f2)
        {
            return ConverStr(GetOperation(f1, f2, OperatorEnum.Add));
        }

        public float Divide(float f1, float f2)
        {
            return ConverStr(GetOperation(f1, f2, OperatorEnum.Divide));
        }

        public float Multiply(float f1, float f2)
        {
            return ConverStr(GetOperation(f1, f2, OperatorEnum.Multiply));
        }

        public float Sub(float f1, float f2)
        {
            return ConverStr(GetOperation(f1, f2, OperatorEnum.Sub));
        }


        //发送UDP 请求得到运算结果
        private string GetOperation(float f1, float f2, OperatorEnum oper)
        {
            lock (RecOperResultStr) 
            {
                RecOperResultStr = string.Empty;
                SendSb.Remove(0, SendSb.Length);
                SendSb.Append(this.EncryptionChar);
                SendSb.Append(f1);
                SendSb.Append(",");
                SendSb.Append(Util.GetEnumDescription(oper));
                SendSb.Append(",");
                SendSb.Append(f2);
                SendSb.Append(this.EncryptionChar);
                byte[] sendBuf = Encoding.UTF8.GetBytes(SendSb.ToString());
                IAsyncResult async = this.SendClient.BeginSend(sendBuf, sendBuf.Length, ServerIpPoint, _ =>
                {
                    UdpClient udpSend = _.AsyncState as UdpClient;
                //获取返回数据
                if (udpSend == null)
                    {
                        return;
                    }
                    byte[] recBuf;
                    try
                    {
                        recBuf = udpSend.Receive(ref RemontIP);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("接收返回值出现错误，{0}", ex.Message);
                        return;
                    }

                    RecOperResultStr = Encoding.UTF8.GetString(recBuf).Replace("*", "");
                    if (string.IsNullOrEmpty(RecOperResultStr))
                    {
                        RecOperResultStr = string.Empty;
                    }
                }, SendClient);
                while (!async.IsCompleted)
                {
                    Thread.Sleep(10);
                }
                return RecOperResultStr;
            }
        }

        private float ConverStr(string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                return float.NaN;
            }
            float f;
            if (!float.TryParse(str, out f))
            {
                return float.NaN;
            }
            return f;
        }
    }


}
